import { encrypt, decrypt } from '@/utils/encrypt';
import dayjs from 'dayjs';
import { markRaw, reactive } from 'vue';
let httpEncryption = true;
export function encryptFn(data: any) {
    return httpEncryption ? encrypt(JSON.stringify(data)) : data;
}
export function decryptFn(data: any) {
    return decrypt(data);
}
// 判断是否为数组
export const isArr = (origin: any): boolean => {
    let str = '[object Array]';
    return Object.prototype.toString.call(origin) == str ? true : false;
};
export function deepClone<T>(origin: T, target?: Record<string, any> | T): T {
    let tar = target || {};

    for (const key in origin) {
        if (Object.prototype.hasOwnProperty.call(origin, key)) {
            if (typeof origin[key] === 'object' && origin[key] !== null) {
                tar[key] = isArr(origin[key]) ? [] : {};
                deepClone(origin[key], tar[key]);
            } else {
                tar[key] = origin[key];
            }
        }
    }
    return tar as T;
}
// 更新tree对应的值
export const findItemById = (list:any[], id:number|string) => {
    // 每次进来使用find遍历一次
    let res = list.find((item: any) => item.id == id);
    if (res) {
        return res;
    } else {
        for (let i = 0; i < list.length; i++) {
            if (list[i].children instanceof Array && list[i].children.length > 0) {
                res = findItemById(list[i].children, id);
                if (res) return res;
            }
        }
        return null;
    }
};
/**
 * 生成随机len位数字
 */
export const randomLenNum: (len: number, date?: boolean) => string = (
    len: number,
    date?: boolean
) => {
    let random = '';
    random = Math.ceil(Math.random() * 100000000000000)
        .toString()
        .substr(0, len || 4);
    if (date) random = random + Date.now();
    return random;
};
export function debounce(func: any, delay?: number) {
    let timer: any;
    return function () {
        const context = this;
        const args = arguments;
        clearTimeout(timer);
        timer = setTimeout(function () {
            func.apply(context, args);
        }, delay || 1000);
    };
}

export function generateUUID(params?: any) {
    const { splitChar = '-' } = params || {};
    let d = new Date().getTime(); // 生成时间戳
    let uuid =
        `xxxxxxxx${splitChar}xxxx${splitChar}4xxx${splitChar}yxxx${splitChar}xxxxxxxxxxxx`.replace(
            /[xy]/g,
            function (c) {
                let r = (d + Math.random() * 16) % 16 | 0;
                d = Math.floor(d / 16);
                return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);
            }
        );
    return uuid;
}

export function throttle(func: any, delay?: number) {
    let timer: any;
    return function () {
        const context = this;
        const args = arguments;
        if (!timer) {
            timer = setTimeout(function () {
                func.apply(context, args);
                timer = null;
            }, 1000);
        }
    };
}
export function classifyByCategory(jsonData, key = 'bId') {
    // 创建一个空对象来存储分类后的结果
    const categorizedData = {};

    // 遍历每个对象
    for (const obj of jsonData) {
        // 获取当前对象的类别
        const category = obj[key];

        // 检查类别是否已经存在于分类结果中
        if (!categorizedData[category]) {
            // 如果类别不存在，则创建一个新数组来存储该类别的对象
            categorizedData[category] = [];
        }

        // 将当前对象添加到对应类别的数组中
        categorizedData[category].push(obj);
    }

    // 返回分类后的结果
    return categorizedData;
}
/**
 * 扁平数据转tree
 * @param {*} menuList 传入的数据
 * @return {*} menus 转化后的树形结构数据
 */
export function getTree(menuList, parentKey, key) {
    const expandedRowKeys = [...new Set(menuList.map((item: any) => item[parentKey]).filter((item: number) => item != -1))];
    let menus=[]    //返回的树结构
    let sourceMap={}    //用传进来的每个项的id作为键值，建立一棵树
    const arr = unRepeat(menuList, key);
    arr.forEach(item=>{
        if (item.childCount) {
            item.children = [];
        }
        sourceMap[item.id]=item    //浅拷贝，共享引用
        if(item.parentId==-1) {
            menus.push(item)
        } else {
            sourceMap[item.parentId]?.children.push(item)
        }
    })
    return {data: menus, expandedRowKeys}; // menus 转化后的树形结构数据
}

/**
 * tree数据扁平
 * @param {Array} data 要扁平化的tree数据
 * @param {string} childrenkey tree children 对应的key
 * @return {*} menus 转化后的扁平化数组
 */
export const dealTreeData = (data: any, childrenkey='children') => {
    let arrTree: any = []
    data.forEach((ele: any) => {
        let obj = { ...ele }
        delete obj[childrenkey]
        arrTree.push(obj)
        if (ele && ele[childrenkey]?.length) {
            arrTree.push(...dealTreeData(ele[childrenkey]))
        }
    });
    return arrTree;
}
// 数组列表转换为树结构列表
// rootId主动设置根节点id为rootId
export function arr2Tree(arr:any, params?:any, resObj = []) {
    try {
        let {
            id = "id",
            parentId = "parentId",
            children = "children",
            rootId,
        } = params || {};
        console.log(id, parentId, children, "");
        const mapObj = new Map();
        let element, operateObj;
        for (let index = 0; index < arr.length; index++) {
            element = arr[index];
            if (!mapObj.has(element[id])) {
                mapObj.set(element[id], element);
            }
            // 判断是不是根节点
            if (!element[parentId] || (rootId && element[parentId] === rootId)) {
                resObj.push(element);
            }
        }
        for (let index = 0; index < arr.length; index++) {
            element = arr[index];
            if (mapObj.has(element[parentId])) {
                operateObj = mapObj.get(element[parentId]);
                operateObj[children] = [
                    ...new Set((operateObj[children] || []).concat(element)),
                ];
            }
            operateObj = null;
        }
        console.log(resObj, "arr2Tree*----------");
        return resObj;
    } catch (e) {
        console.log(e);
    }
}
export function acquireCannayStatus(canarys:any, group:any, index:any) {
    let canary = canarys.desc[group - 1] || 0;
    const stringCanary = canary.toString(2).split('').reverse()[index - 1] || 0;
    return stringCanary == 1;
}
// 将state重置为初始值
export function resetState(state: any, originalData: any, saveOrigin = true) {
    Object.keys(state as Object).forEach((key: string) => {
      const value = originalData[key];
      if (typeof value === 'object' && value !== null) {
        state[key] = resetState(reactive(value), value, saveOrigin)
      } else {
        state[key] = saveOrigin ? markRaw(value) ?? state[key] : markRaw(value);
      }
    })
    return state
}

// 根据key获取父级节点children数组
export function getTreeParentChilds(childs: any = [], findKey: any): any {
    let parentChilds = [];
    for (let i = 0, len = childs.length; i < len; i++) {
        let item = childs[i];
        if (item.id !== findKey && item.children && item.children.length > 0) {
            parentChilds = getTreeParentChilds(item.children, findKey);
        }
        if (item.id == findKey) {
            parentChilds = childs;
        }
        if (parentChilds.length > 0) {
            break;
        }
    }
    return parentChilds;
}


  //查找字典里的某一项
export function arrDicFind(val: string | number, dic: any[], propAlias?: {value: string, label: string }) {
    const item = (dic || []).find(item => item[propAlias?.value || 'value'] === val || item[propAlias?.label || 'label'] === val);
    return item;
}
export const DateTimeFormat = function (value: number | string): string {
    if (!value) return '--';
    if (typeof value === 'number') {
        return dayjs(value).format('YYYY-MM-DD HH:mm:ss');
    } else {
        return dayjs(Number(value)).format('YYYY-MM-DD HH:mm:ss');
    }
};
export const filterOption = (input: string, option: any, fieldNames: any) => {
    return option[fieldNames ? fieldNames.label : 'label'].toLowerCase().indexOf(input.toLowerCase()) >= 0;
};

export function findArrItem(arr: any[], key: any, option?: any) {
    if (!arr?.length) {
        return Promise.reject();
    }
    return new Promise((resolve, reject) => {
        try {
            arr.forEach(item => {
                if (typeof key === 'function' ? key(item[option?.id || 'id']) : item[option?.id || 'id'] === key) {
                    resolve(item);
                    return item;
                } else if (item[option?.children || 'children']?.length) {
                    resolve(findArrItem(item[option?.children || 'children'], key, option));
                }
            })
        } catch (error) {
            reject(error)
        }
    })
}
export function downloadBlob(blob: Blob, saveFileName: string) {
    // 创建 URL 对象
    const url = URL.createObjectURL(blob);
    // 创建链接
    const link = document.createElement('a');
    link.href = url;
    link.download = saveFileName;
    // 模拟点击链接进行下载
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    // 释放 URL 对象
    URL.revokeObjectURL(url);

}
export const getFileByRes = (response: any, downloadFileName?: string, fileType?: string) => {
    fileType = fileType ?? 'xls';
    let saveFileName = '';
    // 获取响应头
    const fileNameEncode = response.headers.get('Content.Disposition')?.split('filename=')[1];
    const fileName = response.url.substring(response.url.lastIndexOf('/') + 1).replace(/^(.+?\..+?)(\?.+$)/g, '$1');
    fileType = fileName.replace(/^(.+)\.(.+$)/g, '$2');
    downloadFileName = downloadFileName || fileName.replace(/^(.+)\.(.+$)/g, '$1');
    saveFileName = fileNameEncode ? decodeURIComponent(fileNameEncode) : `${downloadFileName}.${fileType}`
    const blob = response.blob()
    downloadBlob(blob, saveFileName);
}


/**
 * 扁平化数组转tree：非递归实现 (映射 + 引用), 性能最优
 * 前提：每一项都有parentId，根元素
 * @param { Array } list 数组
 * @param { String } rootId 根元素Id
 * @param { Object } param2 可配置参数
 */
export const buildTree = (arr: any[], rootId: string) => {
    rootId = rootId ?? '-1';
    const list = JSON.parse(JSON.stringify(arr));
    const { idName = 'id', parentIdName = 'parentId', childName = 'children' } = {};
    if (!Array.isArray(list)) {
        new Error('type only Array');
        return list;
    }
    const objMap: any = {}; //暂存数组以 id 为 key的映射关系
    const result = []; // 结果

    for (const item of list) {
        const id = item[idName];
        const parentId = item[parentIdName];

        // 该元素有可能已经放入map中，（找不到该项的parentId时 会先放入map
        objMap[id] = !objMap[id] ? item : { ...item, ...objMap[id] };

        const treeItem = objMap[id]; // 找到映射关系那一项（注意这里是引用）

        if (parentId == rootId) {
            // 已经到根元素则将映射结果放进结果集
            result.push(treeItem);
        } else {
            // 若父元素不存在，初始化父元素
            if (!objMap[parentId]) {
                objMap[parentId] = [];
            }

            // 若无该根元素则放入map中
            if (!objMap[parentId][childName]) {
                objMap[parentId][childName] = [];
            }
            objMap[parentId][childName].push(treeItem);
        }
    }
    return result;
};
export function expandedRow(list: any, branchId: any, rootBranchNodes: any, type: any) {
    const branchIds = branchId ? [branchId] : [];
    let findRootNode = list.find((item: any) =>
        rootBranchNodes.some((row: any) => row.id == item.id)
    );
    let branchList = [];
    let expandedRowKeys = [];
    let loadDeviceBranchIds = [];
    if (!findRootNode) {
        const findCurrentNode = list.find((item: any) =>
            rootBranchNodes.some((row: any) => row.id == item.parentId)
        );
        const findParentNode = rootBranchNodes.find(
            (item: any) => item.id === findCurrentNode?.parentId
        );

        findRootNode = rootBranchNodes.find((item: any) => item.id === findParentNode?.parentId);
        console.log('第一次findParentNode没找到', [...list, findRootNode, findParentNode]);
        //  这里有个bug findRootNode有可能为undefind
        branchList = [...list, findRootNode, findParentNode].filter(Boolean).map((item: any) => {
            return { ...item, isLeaf: !item.childCount && !item.deviceCount };
        });

        console.log(
            '第二次找findParentNode',
            JSON.parse(
                JSON.stringify({
                    list,
                    findCurrentNode,
                    findParentNode: findParentNode?.parentId,
                    findRootNode: findRootNode || null,
                    rootBranchNodes,
                    branchList
                })
            )
        );

        expandedRowKeys = [
            ...new Set(
                [...(branchList.map((item: any) => item.parentId) || []), ...branchIds].filter(
                    (item: number) => item != findRootNode?.parentId
                )
            )
        ];
        loadDeviceBranchIds = branchIds;
        return { expandedRowKeys, loadDeviceBranchIds, branchList, findRootNode };
    }

    branchList = list.map((item: any) => {
        if (type === 'table') {
            const children = !item.childCount ? void 0 : [];
            return { ...item, children };
        }
        return { ...item, isLeaf: !item.childCount && !item.deviceCount };
    });
    expandedRowKeys = [
        ...new Set(
            [...(branchList.map((item: any) => item.parentId) || []), ...branchIds].filter(
                (item: number) => item != findRootNode.parentId
            )
        )
    ];
    loadDeviceBranchIds = branchIds;
    return { expandedRowKeys, loadDeviceBranchIds, branchList, findRootNode };
}